/****************************************************************************

	COPYRIGHT(C) MAXSI SOFTWARE, JONAS 'SORTIE' TERMANSEN 2008, 2009, 2010

    This file is part of Maxsi Engine.

    Maxsi Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Maxsi Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Maxsi Engine. If not, see <http://www.gnu.org/licenses/>.

	*/ #include "MaxsiEngineContributors.h" /*

	If you modify this file, please enter your name below and provide contact
	information in MaxsiEngineContributors.h. For more information please see
	MaxsiEngineContributors.h.
	
	Contributors to this file:

	- Jonas 'Sortie' Termansen
	- [your name here]

	MaxsiEngine.dll
	A linkable version of Maxsi Engine

	MaxsiServer.h
	Basic Winsock Functionallity for server handling

****************************************************************************/

#ifndef MaxsiServer_H
#define MaxsiServer_H

#include <time.h>

// Todo: Clean up this file, remove old commented-out code.

namespace MaxsiEngine
{

	#define	ME_Server_Version	"Application/x-MaxsiEngineServer/1.0 v" __DATE__


	//#define MAX_IN_BUFFER_SIZE	1048576

	#define STATE_DEAD			0
	#define STATE_NOTCONNECTED	0
	#define	STATE_ACCEPTING		1
	#define	STATE_CONNECTING	2
	#define STATE_CONNECTED		3

	#define MAX_CONNECT_SECONDS	10
	#define MAX_SILENT_SECONDS	30

	class	ME_Server;
	class	ME_ServerClient;

	#define	ME_BUFFER_TYPE_WRITE	(1)
	#define	ME_BUFFER_TYPE_READ		(2)

	// Replaced by ME_IO_THINK_*

	#define	ME_NEXT_THINK_NONE			(0)	//	The code haven't requested the next think, if this is unset when the think function ends, there is a bug.
	#define	ME_NEXT_THINK_WINCALLBACK	(1)	//	A completion callback has been requested from Windows.
	#define	ME_NEXT_THINK_MECALLBACK	(2)	//	A completion callback has been requested from another ME_ServerClient service.
	#define	ME_NEXT_THINK_WAIT			(3)	//	Wait NextThinkParam miliseconds then call me.
	#define	ME_NEXT_THINK_DONT			(4)	//	Stop thinking!
	#define	ME_NEXT_THINK_THINKAGAIN	(5)	//	Upon the think's completion, think again.

	#define ScheduleNextThink(Type) ScheduledNextThink(Type,__LINE__,(char*)__FUNCTION__, __FILE__ );

	STRUCTLINK OVERLAPPED_PLUS : public OVERLAPPED
	{
		ME_ServerClient*	Client;
		ME_Server*			Server;
		int					BufferType; // ME_BUFFER_TYPE_*
	};

	class ME_Server;

	CLASSLINK ME_ServerClient
	{
	public:
				ME_ServerClient();
		virtual	~ME_ServerClient();

	public:
		//unsigned long		nWritten;
		//int					nInBufferSize;
		//TODO: REMOVE THIS:
		//WSABUF				buf_out_wsa;
		//CAutoBuffer*		buf_out;		// Data that is to be sent to client
		//char*				buf_in_actual;
		//char*				buf_out_actual;
		//size_t				buf_in_offset;
		//size_t				buf_in_used;
		ME_Buffer*			Input;
		ME_Buffer*			Output;
		OVERLAPPED_PLUS		In;
		OVERLAPPED_PLUS		Out;
		CRITICAL_SECTION	MayExecThinkFunction; // Thread Safety.
		sockaddr_in			LocalAddr;
		sockaddr_in			RemoteAddr;
		time_t				dTimeStamp;

		//void				InitializeInUse();
		//void				DeleteInUse();
		void				TimeStamp();
		time_t				SecondsElapsed();

	public:

		ME_Server*			Server;					// Pointer to the server class that created us!
		//static int			nID;
		//int					nSpecificID;
		SOCKET				Socket;					// Socket used to communicate with client
		int					State();					// Current state of instance
		int					Mode();
		int					Command();
		void				SetMode(int NewMode);
		void				SetCommand(int NewCommand);
		void				SetState(int NewState);
		int					m_Mode;
		int					m_Command;
		int					m_State;
		int					NextThink;
		int					NextThinkParam;
		int					IsWriting;				// Are there data underway?
		int					IsReading;				// Are there data underway?
		bool				IsThinking;				// Are we currently thinking?
		bool				ShouldDisconnect;
		//unsigned long		nRead;
		char*				RemoteHost;
		short				RemotePort;
		// TODO: Update this values!
		size_t				DownSpeed;				// How fast are we recieving data
		size_t				UpSpeed;				// How fast are we sending data

		size_t				PeerId;					//	Unique per-class-instance-per-server identifier.

		virtual		void CALLBACK DoneIO(DWORD dwErrorCode,
							 DWORD dwNumberOfBytesTransferred,
							 LPOVERLAPPED lpOverlapped);


		virtual		bool		Init();				// Attach to a new client
		virtual		bool		Close();				// Detach from a client
		virtual		bool		InitializeBuffers();
		virtual		bool		TerminateBuffers();
		virtual		bool		ScheduledNextThink(int NextThinkType, int Line, char* Function, char* FileName);
		virtual		bool		Think();
		virtual		bool		DoThink();
		virtual		bool		Connect(char* Host);
		virtual		bool		Connected();
		virtual		bool		Disconnected();
		virtual		bool		Write(char* Buffer, size_t BufferLen);
		virtual		bool		Read(size_t Keep); // Read more data, but keep the last Keep bytes of the previous read.
		//virtual		bool		Write(tagPacket *p);	// Add a packet to output buffer
		//virtual		bool		Read(char* Buffer, size_t BufferLen);	// Retrieve a packet from input buffer
		//virtual		bool		OnRecieved(size_t Length); // When Length bytes are recieved
		//virtual		bool		NetWrite();			// Do actual send
		virtual		bool		Disconnect();
		virtual		bool		MaintainConnection();

		virtual		void		OnConnectionAccepted();	// Move from ACCEPTING to CONNECTED state
		
		//virtual		size_t		IN_BUFFER_SIZE( void );
		//virtual		size_t		IN_BUFFER_INC( void );
		//virtual		size_t		OUT_BUF_SIZE( void );

		virtual		void		Maintenance();						// Maintenance
	};

	//CLASSLINK ME_HTTPServerClient : public ME_ServerClient
	//{
	//	Declare_Class(ME_HTTPServerClient, ME_ServerClient);

	//public:
	//	ME_HTTPServerClient();
	//	~ME_HTTPServerClient();

	//public:
	//	virtual		bool	WriteHTTP(char* Buffer, size_t BufferLen);
	//	virtual		bool	WriteHTTPHeaders( void );
	//	virtual		bool	Init();				// Attach to a new client
	//	virtual		bool	Close();				// Detach from a client
	//	virtual		bool	OnRecieved(size_t Length); // When Length bytes are recieved
	//				int		ResponseCode;
	//	virtual		bool	SetResponseCode(int NewResponseCode);
	//	virtual		int		GetResponseCode();
	//				char*	ContentType;
	//	virtual		bool	SetContentType(char* NewContentType);
	//	virtual		char*	GetContentType();
	//				char*	ContentDisposition;
	//	virtual		bool	SetContentDisposition(char* NewContentDisposition);
	//	virtual		char*	GetContentDisposition();
	//				int		ContentLength;
	//	virtual		bool	SetContentLength(int NewContentLength);
	//	virtual		int		GetContentLength();
	//				bool	IsHeadersSent;
	//				List	Headers;
	//				int		FileHandle;
	//				long	FileSize;
	//				long	Left;
	//				char*	Data;

	//};

	CLASSLINK ME_Server // : public ME_Window // it's useful to have a baseclass, but do we really need one?
	{
		//Declare_Class(ME_Server, ME_Window);
	public:

				ME_Server();
		virtual	~ME_Server();

	public:
		virtual	bool	RunServer(short Port) = 0;
		virtual	bool	RunServerEx(short Port, size_t NumConnections, size_t CheckTime) = 0;
		virtual	bool	ShutDown();
		virtual	char*	GetServerInformationHeader();
		virtual	char*	GetServerInformationLine();
		virtual	bool	HandleRequest(ME_ServerClient* Client, char* Parameter = 0) = 0;
		virtual	bool	OpenLogFile(char* Path);
		virtual bool	CloseLogFile();
		virtual bool	ClearLogFile();
		virtual bool	ClearLogFile(char* Path);
		virtual	bool	SetDebugMode(bool IsDebugMode);
		virtual	bool	GetDebugMode();
		//virtual	int		ClientWrote(ME_ServerClient* Client,DWORD dwNumberOfBytesTransferred,OVERLAPPED_PLUS *ov);
		//virtual	int		ClientRead(ME_ServerClient* Client,DWORD dwNumberOfBytesTransferred,OVERLAPPED_PLUS *ov);
		virtual	bool	Log(char* Event);
		virtual	bool	LogDebug(char* Event);
		virtual	bool	LinkToWindow(HWND Window);

	public:
		HWND	WindowHWND;
		size_t	MaxConnections;
		size_t	MaintenanceTime;
		short	Port;
		SOCKET	Listener;
		bool	DebugMode;
		bool	ShouldMainLoop;
		bool	ShouldListen;
		HANDLE	LogFile;

		ME_ServerClient**	Clients;
	};

	#define ME_IOCPServer_MaxConnections (1000)
	#define	ME_IOCPServer_MaintenanceTime (1000)

	// Overlapped I/O: Completion Ports
	CLASSLINK ME_IOCPServer : public ME_Server
	{
		Declare_Class(ME_IOCPServer, ME_Server);

	public:
				ME_IOCPServer();
		virtual	~ME_IOCPServer();

		virtual	bool	RunServer(short Port);
		virtual	bool	RunServerEx(short Port, size_t NumConnections, size_t CheckTime);
		virtual	bool	ShutDown();
		virtual	bool	HandleRequest(ME_ServerClient* Client, char* Parameter = 0);

		void CALLBACK	DoneIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped);

		virtual			ME_ServerClient*	CreateIOCPClient		(void);
		virtual			bool				OnClientCreated			(ME_ServerClient* Client);
		virtual			bool				OnClientConnected		(SOCKET s, int Errror);
		virtual			bool				OnClientDisconnected	(SOCKET s, int Errror);

	public:
		HANDLE	TerminateEvent;
	};

	LINK	void CALLBACK		ME_ServerClient__DoneIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped);

	//// Overlapped I/O: Completion Ports
	//CLASSLINK ME_HTTPServer : public ME_IOCPServer
	//{
	//	Declare_Class(ME_HTTPServer, ME_IOCPServer);
	//public:
	//	ME_HTTPServer();
	//	~ME_HTTPServer();

	//public:
	//	virtual	bool	HandleRequest(ME_ServerClient* Client, char* Parameter = 0);

	//	virtual			ME_ServerClient*	CreateIOCPClient( void );
	//};

	//LINK	int					METestServer();
}
#endif
